package com.pingao.mp.modular.sys.service.impl;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pingao.mp.config.dict.DictConfig;
import com.pingao.mp.config.dict.DictItem;
import com.pingao.mp.modular.sys.entity.Role;
import com.pingao.mp.modular.sys.entity.User;
import com.pingao.mp.modular.sys.mapper.UserMapper;
import com.pingao.mp.modular.sys.service.MenuService;
import com.pingao.mp.modular.sys.service.UserService;
import com.pingao.mp.utils.Constant;
import com.pingao.mp.utils.set.MapBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 闻品高
 * @since 2018-09-26
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private MenuService menuService;
    @Autowired
    private DictConfig dictConfig;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private final static Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Override
    public Map<String, Object> myInfo(User user) {
        Map<String, Object> map = new HashMap<>();
        //判断修改的邮箱是否被其他用户占用
        List<User> emailUsers = baseMapper.selectListJoin(new QueryWrapper<User>().eq(User.COL_EMAIL_JOIN, user.getEmail()).notIn(User.COL_ID_JOIN, user.getId()).isNull(User.COL_DELETE_TIME_JOIN));
        if (emailUsers != null && emailUsers.size() > 0) {
            map.put("status", false);
            map.put("msg", user.getEmail() + "，邮箱已经被其他用户占用，请填写其他邮箱");
            return map;
        }

        if ("".equals(user.getPassword())) {
            user.setPassword(null);
        } else {
            user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8)));
        }
        user.setUpdateTime(LocalDateTime.now());
        if (baseMapper.updateById(user) > 0) {
            map.put("status", true);
            map.put("msg", "修改成功");
        } else {
            map.put("status", false);
            map.put("msg", "修改失败");
        }
        return map;
    }

    @Override
    public String getToken(User user) {
        Date iatDate = new Date();
        Calendar nowTime = Calendar.getInstance();
        nowTime.add(Calendar.HOUR, 24);//token有效时长24个小时，配合前端cookie使用，退出浏览器失效
        Date expiresDate = nowTime.getTime();
        String token = "";
        Set<String> menusForJwt = menuService.getMenusForJwt(user.getId());
        token = JWT.create()
                .withIssuedAt(iatDate) //token生效时间
                .withExpiresAt(expiresDate) //token过期时间
                .withAudience(user.getId().toString()) //存入userId
                //.withClaim("userMenus", JSON.toJSONString(menusForJwt)) //存入用户权限菜单
                .sign(Algorithm.HMAC256(user.getPassword())); //    签名 //这里使用用户的密码
        stringRedisTemplate.opsForValue().set("faraes:mp:userMenus:" + token, JSON.toJSONString(menusForJwt));
        return token;
    }

    @Override
    public User getUserByIdForRoles(Long userId) {
        return baseMapper.selectByIdJoin(userId);
    }

    @Override
    public User get(Long id) {
        return baseMapper.selectByIdJoin(id);
    }

    @Override
    public Set<Role> getRolesByUsername(String username) {
        return null;
    }

    @Override
    public Map<String, Object> getUserList(Integer pageNumber, Integer pageSize, String searchText, String sortName, String sortOrder, List<Long> roleIds, List<Integer> gender, String name, String nick) {
        Map<String, Object> map = new HashMap<>();
        Page<User> page = new Page<>(pageNumber, pageSize);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("1", "1");

        if (searchText != null && !"".equals(searchText)) {
            wrapper.and(q -> q.like(User.COL_NAME_JOIN, searchText).or().like(User.COL_NICK_JOIN, searchText).or().like(User.COL_EMAIL_JOIN, searchText).or().like(User.COL_ADDRESS_JOIN, searchText).or().like(User.COL_ROLE_NAME, searchText));
        }

        if (roleIds != null && roleIds.size() > 0) {
            wrapper.in(User.COL_ROLE_ID_JOIN, roleIds);
        }

        if (gender != null && gender.size() > 0) {
            wrapper.in(User.COL_GENDER_JOIN, gender);
        }

        if (name != null && !name.isEmpty()) {
            wrapper.eq(User.COL_NAME_JOIN, name);
        }

        if (nick != null && !nick.isEmpty()) {
            wrapper.eq(User.COL_NICK_JOIN, nick);
        }

        switch (sortName) {
            case "createTime":
                sortName = User.COL_CREATE_TIME_JOIN;
                break;
            case "updateTime":
                sortName = User.COL_UPDATE_TIME_JOIN;
                break;
            case "roleName":
                sortName = User.COL_ROLE_ID_JOIN;
                break;
        }

        if (sortOrder.equals("desc") || sortOrder.equals("DESC")) {
            wrapper.orderByDesc(sortName);
        } else {
            wrapper.orderByAsc(sortName);
        }

        baseMapper.selectPageJoin(page, wrapper);

        List<User> list = page.getRecords();
        addDictFields(list);
        map.put("rows", list);
        map.put("total", page.getTotal());
        return map;
    }

    @Override
    public Map<String, Object> login(String username, String password, Integer rememberMe) {
        MapBuilder<String, Object> map = new MapBuilder<>();
        map.put("username", username);
        map.put("password", password);
        User user = baseMapper.selectOneJoin(new QueryWrapper<User>().eq(User.COL_NAME_JOIN, username).eq(User.COL_PASSWORD_JOIN, DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8))));
        if (user == null) {
            map.put(Constant.ApiMsg, "登录失败,用户名或密码错误").put(Constant.ApiStatus, false);
        } else {
            map.put("token", this.getToken(user)).put(Constant.ApiData, user).put(Constant.ApiStatus, true).put(Constant.ApiMsg, "登录成功");
        }
        return map.get();
    }

    private void addDictFields(List<User> list) {
        for (User user : list) {
            for (DictItem gender : dictConfig.getGenders()) {
                if (gender.getValue().equals(user.getGender())) {
                    user.setGenderName(gender.getName());
                    break;
                }
            }
        }
    }
}
